/*
 * MIT License
 *
 * Copyright (c) 2023 北京凯特伟业科技有限公司
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */
package com.je.workflow.service.upcoming.complete.impl;

import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import com.google.common.base.Strings;
import com.je.bpm.core.model.BpmnModel;
import com.je.bpm.core.model.FlowElement;
import com.je.bpm.core.model.config.ProcessRemindTypeEnum;
import com.je.bpm.core.model.config.process.ProcessRemindTemplate;
import com.je.bpm.core.model.task.KaiteBaseUserTask;
import com.je.bpm.engine.RepositoryService;
import com.je.bpm.engine.impl.cmd.SubmitTypeEnum;
import com.je.bpm.engine.impl.identity.Authentication;
import com.je.common.base.DynaBean;
import com.je.common.base.mapper.query.Condition;
import com.je.common.base.mapper.query.ConditionEnum;
import com.je.common.base.service.CommonService;
import com.je.common.base.service.MetaService;
import com.je.common.base.spring.SpringContextHolder;
import com.je.common.base.util.DateUtils;
import com.je.ibatis.extension.conditions.ConditionsWrapper;
import com.je.meta.service.QueryBuilderServiceImpl;
import com.je.rbac.rpc.MetaRbacRpcServiceImpl;
import com.je.workflow.service.push.PushService;
import com.je.workflow.service.push.pojo.MessageDTO;
import com.je.workflow.service.upcoming.complete.CompleteUpcomingFactory;
import com.je.workflow.service.upcoming.complete.CompleteUpcomingService;
import com.je.workflow.service.user.WorkFlowUserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.function.Consumer;

@Service
public class AbstractCompleteUpcomingService implements CompleteUpcomingService {

    @Autowired
    MetaService metaService;
    @Autowired
    CommonService commonService;
    @Autowired
    MetaRbacRpcServiceImpl metaRbacRpcService;
    @Autowired
    WorkFlowUserService workFlowUserService;
    @Autowired
    PushService pushService;
    @Autowired
    protected QueryBuilderServiceImpl queryBuilderService;

    @Override
    public void complete(String taskId, String beanId, String comment, String piid, String pdid, Map<String, String> params, Map<String, Object> bean) {

    }

    public DynaBean finishTask(String taskId) {
        return finishTask(taskId, "", false);
    }

    public DynaBean finishTask(String taskId, Boolean otherTaskIsEnd) {
        return finishTask(taskId, "", otherTaskIsEnd);
    }

    public DynaBean finishTask(String taskId, String assigneeId) {
        return finishTask(taskId, assigneeId, false);
    }

    public static String concatenateValues(Set<String> values) {
        return values.stream()
                .map(value -> "'" + value + "'")
                .reduce((result, value) -> result + "," + value)
                .orElse("");
    }

    public DynaBean finishTask(String taskId, String assigneeId, Boolean otherTaskIsEnd) {
        ConditionsWrapper conditionsWrapper = ConditionsWrapper.builder().eq("TASK_ACTIVITI_TASK_ID", taskId);

        List<Condition> conditions = new ArrayList<>();
        conditions.add(buildCondition("TASK_CIRCULATION", "1"));
        Condition condition = new Condition();
        condition.setCn("or");
        condition.setCode("TASK_CIRCULATION");
        condition.setType(ConditionEnum.IS_NULL.getType());
        conditions.add(condition);
        Consumer<ConditionsWrapper> tConsumer = i -> {
            for (Condition c : conditions) {
                queryBuilderService.condition(i, c, null);
            }
        };
        conditionsWrapper.and(tConsumer);
        if (!Strings.isNullOrEmpty(assigneeId)) {
            conditionsWrapper.eq("ASSIGNEE_ID", assigneeId);
        }
        List<DynaBean> dynaBeans = metaService.select("JE_WORKFLOW_RN_TASK",
                conditionsWrapper);
        if (dynaBeans == null) {
            return null;
        }

        if (otherTaskIsEnd) {
            Set<String> nodeIds = new HashSet<>();
            Set<String> piids = new HashSet<>();
            for (DynaBean dynaBean : dynaBeans) {
                nodeIds.add(dynaBean.getStr("TASK_NODE_ID"));
                piids.add(dynaBean.getStr("TASK_PIID"));
            }
            String nodeIdsSql = concatenateValues(nodeIds);
            String piidsSql = concatenateValues(piids);
            if (nodeIdsSql.length() > 0 && piidsSql.length() > 0) {
                metaService.executeSql(String.format("UPDATE JE_WORKFLOW_RN_TASK SET TASK_HANDLE='1' where TASK_HANDLE='0'" +
                                " and TASK_NODE_ID in (%s) and TASK_PIID in (%s) ", nodeIdsSql,
                        piidsSql));
            }

        }

        for (DynaBean dynaBean : dynaBeans) {
            if (otherTaskIsEnd) {
//                metaService.executeSql(String.format("UPDATE JE_WORKFLOW_RN_TASK SET TASK_HANDLE='1' where TASK_HANDLE='0'" +
//                                " and TASK_NODE_ID='%s' and TASK_PIID='%s' ", dynaBean.getStr("TASK_NODE_ID"),
//                        dynaBean.getStr("TASK_PIID")));
            } else {
                dynaBean.setStr("TASK_HANDLE", "1");
                metaService.executeSql(String.format("UPDATE JE_WORKFLOW_RN_TASK SET TASK_HANDLE='1' where %s='%s'", dynaBean.getPkCode(), dynaBean.getPkValue()));
//                metaService.update(dynaBean);
                //如果有待办，直接删除，避免重复数据，查询待办会很慢
                List<DynaBean> list = metaService.select("JE_WORKFLOW_RN_TASK",
                        ConditionsWrapper.builder().eq("ASSIGNEE_ID", dynaBean.getStr("ASSIGNEE_ID"))
                                .eq("TASK_PIID", dynaBean.getStr("TASK_PIID"))
                                .eq("TASK_HANDLE", "0"));
                if (list.size() > 0) {
                    metaService.executeSql(String.format("DELETE FROM JE_WORKFLOW_RN_TASK WHERE ASSIGNEE_ID='%s' and TASK_PIID='%s'" +
                                    " and TASK_HANDLE='1'", dynaBean.getStr("ASSIGNEE_ID"),
                            dynaBean.getStr("TASK_PIID")));
                }
            }
        }
        if (dynaBeans.size() == 0) {
            return null;
        }
        return dynaBeans.get(0);
    }

    public void insertTask(DynaBean dynaBean, String userId, SubmitTypeEnum submitTypeEnum, String comment) {
        if (dynaBean == null) {
            return;
        }
        String executionId = dynaBean.getStr("JE_WORKFLOW_RN_EXECUTION_ID");
        DynaBean accountDept = metaRbacRpcService.selectOneByPk("JE_RBAC_VACCOUNTDEPT", userId);
        DynaBean task = new DynaBean("JE_WORKFLOW_RN_TASK", true);
        task.setStr("TASK_ACTIVITI_TASK_ID", dynaBean.getStr("TASK_ACTIVITI_TASK_ID"));
        task.setStr("TASK_HANDLE", "0");
        task.setStr("TASK_COLLECT_TIME", "");
        task.setStr("TASK_COLLECT", "0");
        task.setStr("TASK_DELAY", "0");
        task.setStr("ASSIGNEE_ID", userId);
        task.setStr("ASSIGNEE_NAME", accountDept.getStr("ACCOUNT_NAME"));
        task.setStr("JE_WORKFLOW_RN_EXECUTION_ID", executionId);
        task.setStr("TASK_NODE_ID", dynaBean.getStr("TASK_NODE_ID"));
        task.setStr("TASK_NODE_NAME", dynaBean.getStr("TASK_NODE_NAME"));
        task.setStr("TASK_PDID", dynaBean.getStr("TASK_PDID"));
        task.setStr("TASK_PIID", dynaBean.getStr("TASK_PIID"));
        commonService.buildModelCreateInfo(task);
        task.setStr("SY_CREATEUSERID", Authentication.getAuthenticatedUser().getDeptId());
        metaService.insert(task);
        metaService.executeSql(String.format("DELETE FROM JE_WORKFLOW_RN_TASK WHERE ASSIGNEE_ID='%s' and TASK_PIID='%s'" +
                " and TASK_HANDLE='1'", userId, dynaBean.getStr("TASK_PIID")));

        //更改所有记录
        DynaBean execution = metaService.selectOneByPk("JE_WORKFLOW_RN_EXECUTION", executionId);
        String assJson = execution.getStr("EXECUTION_ASSIGNEE_JSON");
        execution.setStr("EXECUTION_ASSIGNEE_JSON", updateAssJson(assJson, dynaBean.getStr("TASK_NODE_ID"),
                accountDept.getStr("ACCOUNT_NAME"), userId));
        execution.setStr("EXECUTION_LAST_COMMENT", comment);
        execution.setStr("EXECUTION_SUBMIT_TYPE", submitTypeEnum.toString());
        execution.setStr("EXECUTION_SUBMIT_USER_NAME", Authentication.getAuthenticatedUser().getName());
        execution.setStr("EXECUTION_SUBMIET_USER_ID", Authentication.getAuthenticatedUser().getDeptId());
        execution.setStr("EXECUTION_SUBMIT_TIME", DateUtils.formatDateTime(new Date()));
        metaService.update(execution);

    }

    public String updateAssJson(String json, String nodeId, String userName, String userId) {
        JSONArray jsonArray = JSONArray.parseArray(json);
        for (Object jsonObject : jsonArray) {
            JSONObject object = (JSONObject) jsonObject;
            if (nodeId.equals(object.getString("nodeId"))) {
                object.put("assignee", userId);
                object.put("assigneeName", userName);
            }
        }
        return jsonArray.toJSONString();
    }


    public void invoke(String type, String taskId, String beanId, String comment, String piid, String nodeId, Map<String, String> params, Map<String, Object> bean) {
        CompleteUpcomingFactory.getCompleteUpcomingServiceByType(type).complete(taskId, beanId, comment, piid, nodeId, params, bean);
    }


    public void pushMag(String pdid, String nodeId, String userId, String submitType, String comment,
                        String pkValue, String funcCode, String nodeName, String submitUserName, String submitUserId
            , Map<String, Object> bean) {
        String associationId = workFlowUserService.getAssociationIdById(userId);
        RepositoryService repositoryService = SpringContextHolder.getBean(RepositoryService.class);
        BpmnModel bpmnModel = repositoryService.getBpmnModel(pdid);
        //推送类型
        List<ProcessRemindTypeEnum> processRemindTypeEnumList = bpmnModel.getMainProcess().getMessageSetting().getMessages();
        //推送的模板
        List<ProcessRemindTemplate> messageDefinitions = bpmnModel.getMainProcess().getMessageSetting().getMessageDefinitions();
        FlowElement flowElement = bpmnModel.getMainProcess().getFlowElement(nodeId);
        if (flowElement instanceof KaiteBaseUserTask) {
            KaiteBaseUserTask kaiteBaseUserTask = (KaiteBaseUserTask) flowElement;
            if (!kaiteBaseUserTask.getTaskBasicConfig().getRemind()) {
                String modelName = bpmnModel.getMainProcess().getName();
                pushService.pushDiffTypeMsg(associationId, processRemindTypeEnumList, messageDefinitions,
                        MessageDTO.build(submitType, modelName, comment, pkValue, funcCode, nodeName, submitUserId, submitUserName, bean));
            }
        }
        pushService.pushRefresh(associationId);
    }

    protected DynaBean buildHiExecution(DynaBean execution, SubmitTypeEnum submitType, String comment) {
        DynaBean hiExecution = new DynaBean("JE_WORKFLOW_HI_EXECUTION", true);
        hiExecution.setStr("EXECUTION_STARTER", execution.getStr("EXECUTION_STARTER"));
        hiExecution.setStr("EXECUTION_STARTER_NAME", execution.getStr("EXECUTION_STARTER_NAME"));
        hiExecution.setStr("FUNC_CODE", execution.getStr("FUNC_CODE"));
        hiExecution.setStr("TABLE_CODE", execution.getStr("TABLE_CODE"));
        hiExecution.setStr("FUNC_NAME", execution.getStr("FUNC_NAME"));
        hiExecution.setStr("EXECUTION_TITLE", execution.getStr("EXECUTION_TITLE"));
        hiExecution.setStr("EXECUTION_COMMIT_TYPE", submitType.toString());
        hiExecution.setStr("BUSINESS_KEY", execution.getStr("BUSINESS_KEY"));
        hiExecution.setStr("EXECUTION_COMMENT", comment);
        hiExecution.setStr("JE_WORKFLOW_HI_EXECUTION_ID", UUID.randomUUID().toString());
        hiExecution.setStr("SY_CREATETIME", execution.getStr("SY_CREATETIME"));
        hiExecution.setStr("EXECUTION_PRODUCT_CODE", execution.getStr("EXECUTION_PRODUCT_CODE"));
        hiExecution.setStr("EXECUTION_PROCESS_KEY", execution.getStr("EXECUTION_PROCESS_KEY"));
        hiExecution.setStr("EXECUTION_PDID", execution.getStr("EXECUTION_PDID"));
        hiExecution.setStr("EXECUTION_PIID", execution.getStr("EXECUTION_PIID"));
        hiExecution.setStr("EXECUTION_NODE_ID", execution.getStr("EXECUTION_NODE_ID"));
        hiExecution.setStr("EXECUTION_NODE_NAME", execution.getStr("EXECUTION_NODE_NAME"));
        hiExecution.setStr("EXECUTION_START_TIME", execution.getStr("EXECUTION_START_TIME"));
        hiExecution.setStr("EXECUTION_CONTENT", execution.getStr("EXECUTION_CONTENT"));
        hiExecution.setStr("PROCESS_NAME", execution.getStr("PROCESS_NAME"));
        commonService.buildModelCreateInfo(hiExecution);
        hiExecution.setStr("SY_CREATEUSERID", Authentication.getAuthenticatedUser().getDeptId());
        metaService.insert(hiExecution);
        return hiExecution;
    }

    public Condition buildCondition(String code, String value) {
        Condition condition = new Condition();
        condition.setCn("or");
        condition.setCode(code);
        condition.setValue(value);
        condition.setType(ConditionEnum.NE.getType());
        return condition;
    }

}
